#pragma once

#include "KeyEventListener.h"
#include "CharacterEventListener.h"
#include "MouseEventListener.h"
#include "WindowEventListener.h"
#include "include_gl.h"
#include <set>

/**
	Handler for keyboard and mouse events
*/
class InputHandler
{
public:
	InputHandler(GLFWwindow* window);

	/**
		Returns true iff `button` is held down.
	*/
	bool isMouseDown(int button) const;
	/**
		Returns true iff `button` was pressed down since the last call to `update()`.
	*/
	bool isMousePressed(int button) const;
	/**
		Returns true iff `button` was released since the last call to `update()`.
	*/
	bool isMouseReleased(int button) const;

	/**
		Returns true iff `key` is held down.
	*/
	bool isKeyDown(int key) const;
	/**
		Returns true iff `key` was pressed down since the last call to `update()`.
	*/
	bool isKeyPressed(int key) const;
	/**
		Returns true iff `key` was released since the last call to `update()`.
	*/
	bool isKeyReleased(int key) const;

	int getMouseWheelSpeed() const;

	void addListener(CharacterEventListener* listener);
	void addListener(KeyEventListener* listener);
	void addListener(MouseEventListener* listener);
	void addListener(WindowEventListener* listener);

	void removeListener(CharacterEventListener* listener);
	void removeListener(KeyEventListener* listener);
	void removeListener(MouseEventListener* listener);
	void removeListener(WindowEventListener* listener);

	/**
		Called each frame by the application.
	*/
	void update();

	void mouseButtonCallback(int button, int action, int mods);
	void keyCallback(int key, int scancode, int action, int mods);
	void characterCallback(unsigned int character);
	void scrollCallback(double x, double y);
	void framebufferResizeCallback(int width, int height);
	void windowResizeCallback(int width, int height);

	static InputHandler *globalInputHandler;

private:
	GLFWwindow* _window;

	bool _buttonDown[GLFW_MOUSE_BUTTON_LAST];
	int _buttonPressed[GLFW_MOUSE_BUTTON_LAST];
	int _buttonReleased[GLFW_MOUSE_BUTTON_LAST];

	bool _keyDown[349];
	int _keyPressed[349];
	int _keyReleased[349];

	double _wheelChange;
	int _mouseWheelSpeed;

	std::set<CharacterEventListener*> _characterEventListeners;
	std::set<KeyEventListener*> _keyEventListeners;
	std::set<MouseEventListener*> _mouseEventListeners;
	std::set<WindowEventListener*> _windowEventListeners;
};